package sg.edu.nus.iss.team2s.jass.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import sg.edu.nus.iss.team2s.jass.io.DataAccessI;
/**
 * <p> The <strong>PropertiesUtil</strong> provides the functionality to access(i.e. read or write) 
 * the persisted data.</p>
 * <p> The Singleton Pattern is provided to make sure the <strong>PropertiesUtil</strong> class only
 * has one instance.</p>
 * <p> There are two methods : <code>retrieve(String fileName)</code> and <code>persist(String fileName,List<Object> obj)</code>.
 * The first one is to read the data from properties file. The latter one is to write data to properties file.</p>
 * @author Nie Xiaoyi
 * @version 1.0 2009/09/23
 *
 */
public class PropertiesUtil {
	private static PropertiesUtil dataFileUtility;
	private static String sWorkPath="";
	private static String sWorkFolder = "/data/";
	private Map<String, String> ioConfig = null;
	
	/**
	 * load io data access implementation configuration from xml file, the IO element is as the following:
	 * <IO fileName="User" implementation="sg.edu.nus.iss.team2s.jass.io.UserDataAccessImpl" />
	 * Initially, this method has the io configuration hard-coded here, later it can be refactored to load io configurations from ioConfig.xml
	 */
	private void loadIOConfig(){
		
		ioConfig = new HashMap<String, String>();
		ioConfig.put("User", "sg.edu.nus.iss.team2s.jass.io.UserDataAccessImpl");
		ioConfig.put("JobAdvertResponse", "sg.edu.nus.iss.team2s.jass.io.JobAdvertResponseDataAccessImpl");
		ioConfig.put("JobAdvert", "sg.edu.nus.iss.team2s.jass.io.JobAdvertDataAccessImpl");
		ioConfig.put("Company", "sg.edu.nus.iss.team2s.jass.io.CompanyDataAccessImpl");
		ioConfig.put("Advertiser", "sg.edu.nus.iss.team2s.jass.io.AdvertiserDataAccessImpl");
		ioConfig.put("JobSeeker", "sg.edu.nus.iss.team2s.jass.io.JobSeekerAccessImpl");
	}
	
	//modified by luzhixian, to capture the path correctly.
	private PropertiesUtil() throws Exception{
		String appPath = getClass().getResource(sWorkFolder).getPath();
		sWorkPath = java.net.URLDecoder.decode(appPath, "UTF-8") ; 
	
		if (sWorkPath.startsWith("/")){
		sWorkPath=sWorkPath.substring(1);}

		this.validateFolder(sWorkPath);
		loadIOConfig();
	}
	/**
	 * Create one instance of PropertiesUtil
	 * @return PropertiesUtil
	 * @throws Exception
	 */
	public static synchronized PropertiesUtil getInstance() throws Exception {
		if(dataFileUtility==null){
			dataFileUtility= new PropertiesUtil();
		}
		return dataFileUtility;
	}
	/**
	 * Validate whether the file exists 
	 * @param path the path of file
	 * @throws IOException
	 */
	private void validateFile(String path) throws IOException{		
		File file = new File(path);
	
		if(!file.exists()){
			file.createNewFile();
		}		
	}
	/**
	 * Validate whether the folder exists
	 * @param path the path of folder
	 * @throws IOException
	 */
	private void validateFolder(String path) throws IOException{
		File file = new File(path);
		if(!file.exists()){
			file.mkdir();
		}	
	}
	/**
	 * Read data from specified properties file.
	 * @param fileName the name of properties file.
	 * @return the collection of objects from specified properties file.
	 * @throws Exception
	 */
	public List<Object> retrieve(String fileName) throws Exception
	{
		List<Object> objList = null;
		
		String path = sWorkPath + fileName + ".txt";
		validateFile(path);
		File file = new File(path);
		FileReader reader = new FileReader(file);
		BufferedReader in = new BufferedReader(reader);
		String ioAccessImpl = ioConfig.get(fileName);
		DataAccessI ioAccess = (DataAccessI)Class.forName(ioAccessImpl).newInstance();
		objList = ioAccess.parseObjectsFromReader(in);
		in.close();
		
		return objList;
	}
	/**
	 * Write data to specified properties file.
	 * @param fileName the name of properties file.
	 * @param obj      the data that is update to the specified properties file.
	 * @return if the operation is success, the return value is true. otherwise the return value is false. 
	 * @throws Exception
	 */
	public boolean persist(String fileName,List<Object> obj) throws Exception{
		boolean result = true;
		String path = sWorkPath + fileName + ".txt";
		validateFile(path);
		File file = new File(path);
		FileWriter writer = new FileWriter(file);
		BufferedWriter out = new BufferedWriter(writer);
		String ioAccessImpl = ioConfig.get(fileName);
		DataAccessI ioAccess = (DataAccessI)Class.forName(ioAccessImpl).newInstance();
		ioAccess.writeObjectsToWriter(obj, out);
		out.close();
		return result;
	}
}
